/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/02/18
* File: enn_color.h
**/

#pragma once

#include "enn_vector4.h"

namespace enn
{
/// RGBA color.
class Color
{
public:
	/// Construct with default values (opaque white.)
	Color() :
	  r_(1.0f),
		  g_(1.0f),
		  b_(1.0f),
		  a_(1.0f)
	  {
	  }

	  /// Copy-construct from another color.
	  Color(const Color& color) :
	  r_(color.r_),
		  g_(color.g_),
		  b_(color.b_),
		  a_(color.a_)
	  {
	  }

	  /// Construct from another color and modify the alpha.
	  Color(const Color& color, float a) :
	  r_(color.r_),
		  g_(color.g_),
		  b_(color.b_),
		  a_(a)
	  {
	  }

	  /// Construct from RGB values and set alpha fully opaque.
	  Color(float r, float g, float b) :
	  r_(r),
		  g_(g),
		  b_(b),
		  a_(1.0f)
	  {
	  }

	  /// Construct from RGBA values.
	  Color(float r, float g, float b, float a) :
	  r_(r),
		  g_(g),
		  b_(b),
		  a_(a)
	  {
	  }

	  /// Test for equality with another color.
	  bool operator == (const Color& rhs) const { return Equals(r_, rhs.r_) && Equals(g_, rhs.g_) && Equals(b_, rhs.b_) && Equals(a_, rhs.a_); }
	  /// Test for inequality with another color.
	  bool operator != (const Color& rhs) const { return !Equals(r_, rhs.r_) || !Equals(g_, rhs.g_) || !Equals(b_, rhs.b_) || !Equals(a_, rhs.a_); }
	  /// Multiply with a scalar.
	  Color operator * (float rhs) const { return Color(r_ * rhs, g_ * rhs, b_ * rhs, a_ * rhs); }
	  /// Add a color.
	  Color operator + (const Color& rhs) const { return Color(r_ + rhs.r_, g_ + rhs.g_, b_ + rhs.b_, a_ + rhs.a_); }

	  /// Add-assign a color.
	  Color& operator += (const Color& rhs)
	  {
		  r_ += rhs.r_;
		  g_ += rhs.g_;
		  b_ += rhs.b_;
		  a_ += rhs.a_;
		  return *this;
	  }

	  /// Return float data.
	  const float* Data() const { return &r_; }
	  /// Return RGB values as a vec3f.
	  vec3f RGBValues() const { return vec3f(r_, g_, b_); }
	  /// Return approximate intensity.
	  float Intensity() const { return RGBValues().DotProduct(vec3f(0.333f, 0.333f, 0.333f)); }

	  /// Linear interpolation with another color.
	  Color Lerp(const Color& rhs, float t) const
	  {
		  float invT = 1.0f - t;
		  return Color(
			  r_ * invT + rhs.r_ * t,
			  g_ * invT + rhs.g_ * t,
			  b_ * invT + rhs.b_ * t,
			  a_ * invT + rhs.a_ * t
			  );
	  }

	  /// Return color packed to a 32-bit integer. Components are clamped to [0, 1] range.
	  unsigned ToUInt() const
	  {
		  unsigned r = Clamp(((int)(r_ * 255.0f)), 0, 255);
		  unsigned g = Clamp(((int)(g_ * 255.0f)), 0, 255);
		  unsigned b = Clamp(((int)(b_ * 255.0f)), 0, 255);
		  unsigned a = Clamp(((int)(a_ * 255.0f)), 0, 255);
		  return (a << 24) | (b << 16) | (g << 8) | r;
	  }

	  /// Return as a four-dimensional vector.
	  vec4f Tovec4f() const { return vec4f(r_, g_, b_, a_); }

	  /// Red value.
	  float r_;
	  /// Green value.
	  float g_;
	  /// Blue value.
	  float b_;
	  /// Alpha value.
	  float a_;

	  /// Opaque white color.
	  static const Color WHITE;
	  /// Opaque yellow color.
	  static const Color YELLOW;
	  /// Opaque red color.
	  static const Color RED;
	  /// Opaque green color.
	  static const Color GREEN;
	  /// Opaque green color.
	  static const Color BLUE;
	  /// Opaque black color.
	  static const Color BLACK;
};

/// Multiply Color with a scalar.
inline Color operator * (float lhs, const Color& rhs) { return rhs * lhs; }

/// Color-time pair for color interpolation.
class ColorFade
{
public:
	/// Construct with default color and zero time.
	ColorFade() :
	  time_(0.0f)
	  {
	  }

	  /// Construct with a color and zero time.
	  ColorFade(const Color& color) :
	  color_(color),
		  time_(0.0f)
	  {
	  }

	  /// Construct from a color and time.
	  ColorFade(const Color& color, float time) :
	  color_(color),
		  time_(time)
	  {
	  }

	  /// Return interpolated value with another color-time pair, at the time specified.
	  Color interpolate(const ColorFade& next, float time)
	  {
		  float timeInterval = next.time_ - time_;
		  if (timeInterval > 0.0f)
		  {
			  float t = (time - time_) / timeInterval;
			  return color_.Lerp(next.color_, t);
		  }
		  else
			  return next.color_;
	  }

	  /// Color.
	  Color color_;
	  /// Time.
	  float time_;
};

}